import operator
from os import listdir
import numpy
from PIL import Image
from pylab import *

#函数说明：KNN算法分类器
def classfy(testset, dataset, labels, k):
    dataset_size = dataset.shape[0]#返回训练数据集的行数
    diffmat = numpy.tile(testset, (dataset_size, 1)) - dataset
    sqdiffmat = diffmat**2 #套入公式
    sqdistance = sqdiffmat.sum(axis=1)
    distance = sqdistance**0.5
    sorteddistance = distance.argsort()#返回元素从小到大排序后的索引值
    classcount = {}#记录类别次数的字典
    for i in range(k):
        votallabel = labels[sorteddistance[i]]#取出前k个的类别
        classcount[votallabel] = classcount.get(votallabel, 0) + 1#字典中对应类别加1
    sortedclasscount = sorted(classcount.items(), key=operator.itemgetter(1), reverse=True)#按各类别次数降序排序字典
    return sortedclasscount[0][0]#返回次数最多的类别


#函数说明：将图像文本转换为图片向量进行处理
def conversion(filename):
    return_vect = np.zeros((1, 784))#图片长宽28，
    fh = open(filename)
    for i in range(28):
        line = fh.readline()
        for j in range(28):
            return_vect[0, 28*i+j] = int(line[j])
    return return_vect

#函数说明：测试分类器
def hand_writing_test():
    hwlabels = []#测试集的标签
    training_file_list = listdir('trainingDigits')#初始化训练的矩阵
    num1 = len(training_file_list)
    training_mat = np.zeros((num1, 784))
    for i in range(num1):
        filename_str = training_file_list[i]#文件名
        file_str = filename_str.split('.')[0]
        label_str = int(file_str.split('_')[0])#获得分类标签，并添加到测试集标签中
        hwlabels.append(label_str)
        filename1 = 'trainingDigits\\'
        training_mat[i, :] = conversion(filename1 + filename_str)#将每一个文本文件存储到矩阵中
    testing_file_list = listdir('testDigits')
    error_rate = 0.0#初始化错误的个数
    num2 = len(testing_file_list)
    for j in range(num2):
        filename_str2 = testing_file_list[j]
        file_str2 = filename_str2.split('.')[0]
        label_str2 = int(file_str2.split('_')[0])
        filename2 = 'testDigits\\'
        vect_test = conversion(filename2 + filename_str2)
        classify_result = classfy(vect_test, training_mat, hwlabels, 1)
        print("识别之后的结果为：%d, 真实结果为：%d" % (classify_result, label_str2))
        if(classify_result != label_str2):
            error_rate += 1
    print("总共错了几个数据：%d\n 错误率为：%f" % (error_rate, (error_rate/float(num2))))


if __name__ == '__main__':
    hand_writing_test()